#include "Common.hpp"
#include "Log.hpp"
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace LogModule;

int main(int argc,char* argv[])
{
    ENABLE_CONSOLE_LOG();
    if(argc != 3)
    {
        LOG(LogLevel::ERROR) << "Usage : " << argv[0] << " serverip serverport ";
        Die(1);
    }
    //创建套接字
    int sockfd = ::socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd < 0)
    {
        LOG(LogLevel::ERROR) << "socket : " << strerror(errno);
        Die(1);
    }
    std::string serverip = argv[1];
    uint16_t serverport = std::stoi(argv[2]);
    //填充网络字段+bind
    //但客户端不需要bind,因为首次调用sendto之后OS自动会bind，并且客户端不需要一个固定的端口号
    struct sockaddr_in server;
    memset(&server,0,sizeof(server));
    server.sin_addr.s_addr = ::inet_addr(serverip.c_str());
    server.sin_family = AF_INET;//套接字需要的协议簇
    server.sin_port = htons(serverport);
    socklen_t len = sizeof(server);
    while(true)
    {
        std::cout << "please say# ";
        std::string message;
        std::cin >> message;
        ssize_t n = ::sendto(sockfd,message.c_str(),message.size(),0,CONV(&server),len);
        (void) n;

        //接收服务器发送过来的消息
        struct sockaddr_in temp;
        socklen_t tlen = sizeof(temp);//用于知道temp所用协议和地址类型，不同网络协议和地址类型（如IPV4和IPV6）的地址长度可能不同
        // 确认地址信息是否完整
        // 如果 addrlen 的值小于你最初设置的大小，说明实际填充的地址信息长度小于缓冲区的大小，地址信息是完整的。
        // 如果 addrlen 的值等于你最初设置的大小，可能表示地址信息被截断了（虽然在大多数情况下，地址信息不会被截断，因为常见的地址类型如 IPv4 的地址长度是固定的）。
        // 动态处理不同地址类型
        // 在某些情况下，你的程序可能需要处理不同类型的地址（如 IPv4 和 IPv6）。通过检查 addrlen 的值，你可以确定接收到的地址是 IPv4 还是 IPv6，因为它们的地址长度不同。

        char buffer[1024];
        n = ::recvfrom(sockfd,buffer,sizeof(buffer) - 1,0,CONV(&temp),&tlen);
        if(n > 0)
        {
            buffer[n] = 0;
            std::cout << buffer << std::endl;
        }

    }


    return 0;
}